package com.gitee.loyo.act

import java.math.BigDecimal

interface AggregateFunction{

    fun <T: Any> count(column: Column<T>): Column<T>

    fun <T: Any> sum(column: Column<T>): Column<T>

    fun <T: Any> max(column: Column<T>): Column<T>

    fun <T: Any> min(column: Column<T>): Column<T>

    fun <T: Any> avg(column: Column<T>): Column<T>

}

object AggregateFunctionDelegate: AggregateFunction{

    override fun <T: Any> count(column: Column<T>): Column<T>{
        return addAggregate(column, "count")
    }

    override fun <T: Any> sum(column: Column<T>): Column<T>{
        return addAggregate(column, "sum")
    }

    override fun <T: Any> max(column: Column<T>): Column<T>{
        return addAggregate(column, "max")
    }

    override fun <T: Any> min(column: Column<T>): Column<T>{
        return addAggregate(column, "min")
    }

    override fun <T: Any> avg(column: Column<T>): Column<T>{
        return addAggregate(column, "avg")
    }

    private fun <T: Any> addAggregate(column: Column<T>, funName: String): Column<T>{
        return Column<T>(column).apply {
            nameHandler = { "$funName($it)" }
        }
    }
}

interface SQLFunction{

    fun length(column: Column<String>): Column<Int>

    fun instr(column: Column<String>, substr: String): Column<Int>

    fun substr(column: Column<String>, start: Int): Column<String>

    fun substr(column: Column<String>, start: Int, length: Int): Column<String>

    fun round(column: Column<BigDecimal>): Column<Int>

    fun ceil(column: Column<BigDecimal>): Column<Int>

    fun floor(column: Column<BigDecimal>): Column<Int>

    fun mod(column: Column<Int>, n: Int): Column<Int>

    fun mod(column: Column<Long>, n: Long): Column<Long>
}

object SQLFunctionDelegate: SQLFunction{

    override fun length(column: Column<String>): Column<Int> {
        return Column<Int>(column).apply {
            nameHandler = { "length($it)" }
        }
    }

    override fun instr(column: Column<String>, substr: String): Column<Int> {
        return LiteralColumn<Int>(column, substr).apply {
            nameHandler = { "instr($it, ?)" }
        }
    }

    override fun substr(column: Column<String>, start: Int): Column<String> {
        return Column<String>(column).apply {
            nameHandler = { "substr($it, $start)" }
        }
    }

    override fun substr(column: Column<String>, start: Int, length: Int): Column<String> {
        return Column<String>(column).apply {
            nameHandler = { "substr($it, $start, $length)" }
        }
    }

    override fun round(column: Column<BigDecimal>): Column<Int> {
        return Column<Int>(column).apply {
            nameHandler = { "round($it)" }
        }
    }

    override fun ceil(column: Column<BigDecimal>): Column<Int> {
        return Column<Int>(column).apply {
            nameHandler = { "ceil($it)" }
        }
    }

    override fun floor(column: Column<BigDecimal>): Column<Int> {
        return Column<Int>(column).apply {
            nameHandler = { "floor($it)" }
        }
    }

    override fun mod(column: Column<Int>, n: Int): Column<Int> {
        return LiteralColumn<Int>(column, n).apply {
            nameHandler = { "mod($it, ?)" }
        }
    }

    override fun mod(column: Column<Long>, n: Long): Column<Long> {
        return LiteralColumn<Long>(column, n).apply {
            nameHandler = { "mod($it, ?)" }
        }
    }

}